#pragma once
#pragma once
#include "Common.h"

//定长内存池
template <class T>
class ObjectPool
{
public:
	T *New()
	{
		objMtx.lock();
		T *obj = nullptr;
		//优先把链表中的内存块拿来用
		if (_freeList)
		{
			void *next = *(void **)_freeList;
			obj = (T *)_freeList;
			_freeList = next;
		}
		else
		{
			//给obj的空间至少能存下一个指针的大小
			//否则无法链接链表
			size_t objSize = sizeof(T) < sizeof(void *) ? sizeof(void *) : sizeof(T);

			//大块空间用完，或者还没开辟，或者剩下的空间不够了
			if (_remainBytes < objSize)
			{
				//开辟一大块内存
				//_memory = (char*)malloc(_memorySize);

				//大块内存也有可能存不下T
				size_t _NewMemorySize = sizeof(T) > _memorySize ? sizeof(T) : _memorySize;
				_memory = (char *)SystemAlloc(_NewMemorySize >> 13);
				if (_memory == nullptr)
				{
					//开辟失败
					throw std::bad_alloc();
				}
				_remainBytes = _NewMemorySize;
			}
			obj = (T *)_memory;

			_memory += objSize;
			_remainBytes -= objSize;
		}
		//调用定位new进行初始化
		new (obj) T;
		objMtx.unlock();

		return obj;
	}
	void Delete(T *obj)
	{
		objMtx.lock();

		//显示调用析构函数
		obj->~T();

		//找到空间前4/8个字节，然后头插
		*(void **)obj = _freeList;
		_freeList = obj;

		objMtx.unlock();
	}

private:
	//向系统要一大块内存
	//用char类型更容易往后切空间
	char *_memory = nullptr;
	//大块内存每次要多少字节
	const size_t _memorySize = 1024 * 128;
	//大块切分后内存剩余的空间大小
	size_t _remainBytes = 0;

	//加个锁，防止多线程调用定长内存池时冲突
	std::mutex objMtx;

	//用来挂接释放的空间，形成链表
	void *_freeList = nullptr;
};

/*
#include "Common.h"

//#ifdef _WIN32
//	#include <windows.h> // windows下
//#else
//	// linux下brk mmap等
//#endif

//定长内存池
//template<size_t N>
//class ObjectPool
//{};

// 直接去堆上按页申请空间
//inline static void* SystemAlloc(size_t kpage)
//{
//#ifdef _WIN32
//	void* ptr = VirtualAlloc(0, kpage * (1 << 12), MEM_COMMIT | MEM_RESERVE,
//		PAGE_READWRITE);
//#else
//	// linux下brk mmap等
//#endif
//	if (ptr == nullptr)
//		throw std::bad_alloc();
//	return ptr;
//}

//定长内存池是针对发单一场景，对象大小是定长的
template<class T>
class ObjectPool
{
public: 
	T* New()
	{
		T* obj = nullptr;

		// 优先使用还回来的内存块，重复利用
		if (_freeList)
		{
			void* next = *((void**)_freeList);
			obj = (T*)_freeList;
			_freeList = next;
		}
		else
		{
			// 剩余内存不够一个对象大小时，重新开大块空间
			if (_remainBytes < sizeof(T))
			{
				_remainBytes = 128 * 1024;
				//_memory = (char*)malloc(_remainBytes); // 申请4KB内存
				_memory = (char*)SystemAlloc(_remainBytes >> 13);
				if (_memory == nullptr)
				{
					throw std::bad_alloc();// 抛异常退出
				}
			}

			obj = (T*)_memory; // 申请一个T类型大小的对象

			// 如果obj对象大小小于一个指针，那就给一个指针
			size_t objSize = sizeof(T) < sizeof(void*) ? sizeof(void*) : sizeof(T);

			_memory += objSize; //内存指针向后偏移
			_remainBytes -= objSize;
		}

		// 定位new，对于已有的T，显示调用T的构造函数初始化
		new(obj) T;

		return obj;
	}

	void Delete(T* obj)
	{
		// 显示调用析构函数清理对象
		obj->~T(); 

		if (_freeList == nullptr)
		{
			_freeList = obj;
			//if (sizeof(int*) == 4) *(int*)obj = nullptr; // 32位
			//else *(long long*)obj = nullptr; // 64位

			*((void**)obj) = nullptr; // 解引用指针的指针
			//*((T**)obj) = nullptr; // 只要是二级指针就可以
		}
		else
		{
			// 头插
			*((void**)obj) = _freeList;
			_freeList = obj;
		}

		//*((void**)obj) = _freeList;
		//_freeList = obj;
	}

private:
	char* _memory = nullptr;   // 指向内存块的指针
	size_t _remainBytes = 0;      // 内存剩余的空间大小
	
	void* _freeList = nullptr; // 管理还回来的内存对象的自由链表
};
*/


/*
struct TreeNode
{
	int _val;
	TreeNode* _left;
	TreeNode* _right;
	TreeNode()
		:_val(0)
		, _left(nullptr)
		, _right(nullptr)
	{}
};

void TestObjectPool()
{
	// 申请释放的轮次
	const size_t Rounds = 5;

	// 每轮申请释放多少次
	const size_t N = 100000;
	
	size_t begin1 = clock();
	std::vector<TreeNode*> v1;
	v1.reserve(N);
	
	for (size_t j = 0; j < Rounds; ++j)
	{
		for (int i = 0; i < N; ++i)
		{
			v1.push_back(new TreeNode);
		}
		for (int i = 0; i < N; ++i)
		{
			delete v1[i];
		}
		v1.clear();
	}
	
	size_t end1 = clock();
	ObjectPool<TreeNode> TNPool;
	
	size_t begin2 = clock();
	std::vector<TreeNode*> v2;
	v2.reserve(N);
	
	for (size_t j = 0; j < Rounds; ++j)
	{
		for (int i = 0; i < N; ++i)
		{
			v2.push_back(TNPool.New());
		}
		for (int i = 0; i < 100000; ++i)
		{
			TNPool.Delete(v2[i]);
		}
		v2.clear();
	}
	
	size_t end2 = clock();
	
	cout << "new cost time:" << end1 - begin1 << endl;
	cout << "object pool cost time:" << end2 - begin2 << endl;
}
*/